/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef DECLARATORS_H
#define DECLARATORS_H

#include "actions.h"
#include "directives.h"
#include "cnome.h"
#include "tokens.h"

namespace cnome {
template <typename ScannerT>
void
cpp::definition<ScannerT>::declarators(cpp const& self)
    {
            using namespace actions;
            using namespace directive;
            using namespace util;

            init_declarator_list =
                init_declarator >> init_declarator_list_helper 
            ;

            init_declarator_list_helper =
                ( COMMA >> init_declarator >> init_declarator_list_helper ) |
                EPSILON
            ;

            init_declarator =
                remain_scope_d[
                    if_p(
                        lookahead_d[
                            remain_scope_d[declarator >> LEFTBRACKET]] )
                        [NOTHING].else_p
                        [ pdf_d[ declarator[&newMember]] >> !initializer ] 
                ]
            ;

            declarator =
                    (    direct_declarator 
                      |  ( ptr_operator >> declarator ) ) 
                >>    if_p(lookahead_d[LEFTPAREN])[
                          if_p(lookahead_d[initializer])[EPSILON].
                          else_p[NOTHING] ].
                      else_p[EPSILON]
            ;

            direct_declarator =
                    ( remain_scope_d[declarator_id[&enterMethodScp] >> direct_declarator_helper]            ) 
				|   ( (remain_scope_d[ LEFTPAREN >> declarator >> RIGHTPAREN] ) >> direct_declarator_helper )
            ;

            direct_declarator_helper =
                    ( 
                            ( 
                                    (        remain_scope_d[ 
										        pdl_d[ 
                                                        LEFTPAREN[&declareTmplPrms][&newParenMethod]
                                                    >>  parameter_declaration_clause 
                                                    >>  RIGHTPAREN[&newParenMethod]
												]
                                            ]
                                        >>  !cv_qualifier_seq 
                                        >> !exception_specification 
                                    ) 
                                |    ( LEFTBRACKET >> !constant_expression >> RIGHTBRACKET )              
                            ) 
                        >>  direct_declarator_helper
                    )  
                |    EPSILON
            ;

            ptr_operator =
                    ( STAR >> !cv_qualifier_seq ) 
                |    ( cv_qualifier_seq >> STAR  )  // Microsoft specific
                |    AND 
                |    remain_scope_d[
                        sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] 
                            >> nested_name_specifier ] >> STAR >> !cv_qualifier_seq ]
            ;

            cv_qualifier_seq =
                cv_qualifier >> !cv_qualifier_seq
            ;

            cv_qualifier =
                CONST_ | VOLATILE
            ;

            declarator_id =
                remain_scope_d[
                        ( sss_d[ !COLON_COLON[&scopeIsAbsolut][&enter_scope] >> id_expression ] ) 
                    |   ( sss_d[ !(COLON_COLON[&scopeIsAbsolut][&enter_scope]) >> !nested_name_specifier >> type_name ] ) ]
            ;

            type_id =
                type_specifier_seq >> !abstract_declarator
            ;

            type_specifier_seq =
                type_specifier >> !type_specifier_seq
            ;

            abstract_declarator =
                ( ptr_operator >> !abstract_declarator) |
                direct_abstract_declarator
            ;

            direct_abstract_declarator =
                ( LEFTPAREN >> abstract_declarator >> RIGHTPAREN) >> 
                direct_abstract_declarator_helper
            ;

            direct_abstract_declarator_helper =
                    (        remain_scope_d[ 
				                pdl_d[ 

                                        LEFTPAREN[&declareTmplPrms][&newParenMethod] 
                                    >>  parameter_declaration_clause 
                                    >>  RIGHTPAREN[&newParenMethod]
								]
                            ]
                        >>    !cv_qualifier_seq 
                        >>    !exception_specification                                                           
                    )
                |    ( LEFTBRACKET >> !constant_expression >> RIGHTBRACKET )
                |    EPSILON
            ;

            parameter_declaration_clause =
	  		      if_p(parameter_declaration_list >> COMMA >> ELLIPSIS[&newPrm][&newPrmVar])[EPSILON].
				  else_p[EPSILON[&clearPrmLevel] >> NOTHING]
               |  if_p(parameter_declaration_list >> !(ELLIPSIS[&newPrm][&newPrmVar]) 
				    >> if_p(lookahead_d[COMMA])[NOTHING].else_p[EPSILON])[EPSILON].
				  else_p[EPSILON[&clearPrmLevel] >> NOTHING]
               |  if_p(!(ELLIPSIS[&newPrm][&newPrmVar]))[EPSILON].
			      else_p[EPSILON[&clearPrmLevel] >> NOTHING]
            ;

            parameter_declaration_list =
				//EPSILON[&declareTmplPrms] >> 
				parameter_declaration >> parameter_declaration_list_helper
            ;

            parameter_declaration_list_helper =
                ( COMMA >> parameter_declaration >> parameter_declaration_list_helper ) |
                EPSILON
            ;

            parameter_declaration =
                    clear_type_d [    
                            decl_specifier_seq[&newTypeSpc][&newPrm]  
                        >>    if_p(
                                remain_scope_d[ 
                                       declarator[&newPrmVar] ]
                                    >> !( ASSIGN >> remain_scope_d[assignment_expression]) 
                                )[EPSILON].                                                
                            else_p[EPSILON[&cancelLastPrm] >> NOTHING]                     
                    ]                                                                       //                     |
                // TODO: Verify if it will be necessary to use remain_scope_d and remain_type_d 
                // for abstract_declarator
                |    clear_type_d [ 
                              decl_specifier_seq[&newTypeSpc][&newPrm] 
                          >>  (     remain_scope_d[abstract_declarator >> !(ASSIGN >> assignment_expression) ] 
						         |  remain_scope_d[ASSIGN >> assignment_expression ] 
								 |	EPSILON ) ]
            ;

            function_definition =  // TODO: Verify if function_definition is correct
                    remain_scope_d[
                            remain_type_d[
                                      decl_specifier_seq[&newTypeSpc]
                                >>    pdf_d[declarator[&newMethod]] 
                            ]
                        >>  !ctor_initializer >> function_body 
                    ]
                |   remain_scope_d[
                            remain_type_d[ pdf_d[declarator[&newMethod]] ] 
                        >>	!ctor_initializer >> function_body 
                    ]
                |   remain_scope_d[
                            remain_type_d[ 
                                    decl_specifier_seq[&newTypeSpc]
                                >>	pdf_d[declarator[&newMethod]] 
                            ]
                        >>	function_try_block 
                    ]
                |   remain_scope_d[
                            remain_type_d[ pdf_d[declarator[&newMethod]] ]
                        >>	function_try_block 
                    ]
                |   (EPSILON[&cancelDecl] >> NOTHING)
            ;

            function_body =
                    EPSILON[&inFunction_body] 
                >>    if_p(compound_statement)[EPSILON[&defMethod][&outFunction_body]].
                    else_p[EPSILON[&outFunction_body]>>NOTHING]
            ;

            initializer =
                ( ASSIGN >> initializer_clause ) |
                ( LEFTPAREN >> expression_list >> RIGHTPAREN )
            ;

            initializer_clause =
                assignment_expression                                     |
                ( LEFTBRACE >> initializer_list >> !COMMA >> RIGHTBRACE ) |
                ( LEFTBRACE >> RIGHTBRACE )
            ;

            initializer_list =
                initializer_clause >> initializer_list_helper
            ;

            initializer_list_helper =
                ( COMMA >> initializer_clause >> initializer_list_helper ) |
                EPSILON
            ;
            //  End grammar definition
          
            // turn on the debugging info.
            BOOST_SPIRIT_DEBUG_RULE(init_declarator_list);
            BOOST_SPIRIT_DEBUG_RULE(init_declarator);
            BOOST_SPIRIT_DEBUG_RULE(init_declarator_list_helper);
            BOOST_SPIRIT_DEBUG_RULE(declarator);
            BOOST_SPIRIT_DEBUG_RULE(initializer);
            BOOST_SPIRIT_DEBUG_RULE(ptr_operator);
            BOOST_SPIRIT_DEBUG_RULE(parameter_declaration_clause);
            BOOST_SPIRIT_DEBUG_RULE(cv_qualifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(nested_name_specifier);
            BOOST_SPIRIT_DEBUG_RULE(id_expression);
            BOOST_SPIRIT_DEBUG_RULE(type_id);
            BOOST_SPIRIT_DEBUG_RULE(abstract_declarator);
            BOOST_SPIRIT_DEBUG_RULE(type_specifier);
            BOOST_SPIRIT_DEBUG_RULE(type_name);
            BOOST_SPIRIT_DEBUG_RULE(assignment_expression);
            BOOST_SPIRIT_DEBUG_RULE(initializer_clause);
            BOOST_SPIRIT_DEBUG_RULE(expression_list);
            BOOST_SPIRIT_DEBUG_RULE(initializer_list);
            BOOST_SPIRIT_DEBUG_RULE(initializer_list_helper);
            BOOST_SPIRIT_DEBUG_RULE(function_definition);
            BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(function_body);
            BOOST_SPIRIT_DEBUG_RULE(function_try_block);
            BOOST_SPIRIT_DEBUG_RULE(ctor_initializer);
            BOOST_SPIRIT_DEBUG_RULE(compound_statement);
            BOOST_SPIRIT_DEBUG_RULE(declarator);
            BOOST_SPIRIT_DEBUG_RULE(direct_declarator);
            BOOST_SPIRIT_DEBUG_RULE(ptr_operator);
            BOOST_SPIRIT_DEBUG_RULE(declarator_id);
            BOOST_SPIRIT_DEBUG_RULE(direct_declarator_helper);
            BOOST_SPIRIT_DEBUG_RULE(cv_qualifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(exception_specification);
            BOOST_SPIRIT_DEBUG_RULE(constant_expression);
            BOOST_SPIRIT_DEBUG_RULE(nested_name_specifier);
            BOOST_SPIRIT_DEBUG_RULE(id_expression);
            BOOST_SPIRIT_DEBUG_RULE(type_id);
            BOOST_SPIRIT_DEBUG_RULE(type_specifier);
            BOOST_SPIRIT_DEBUG_RULE(type_name);
            BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(type_id);
            BOOST_SPIRIT_DEBUG_RULE(type_specifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(abstract_declarator);
            BOOST_SPIRIT_DEBUG_RULE(abstract_declarator);
            BOOST_SPIRIT_DEBUG_RULE(ptr_operator);
            BOOST_SPIRIT_DEBUG_RULE(direct_abstract_declarator);
            BOOST_SPIRIT_DEBUG_RULE(direct_abstract_declarator_helper);
            BOOST_SPIRIT_DEBUG_RULE(parameter_declaration_list);
            BOOST_SPIRIT_DEBUG_RULE(exception_specification);
            BOOST_SPIRIT_DEBUG_RULE(constant_expression);
            BOOST_SPIRIT_DEBUG_RULE(cv_qualifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(cv_qualifier);
            BOOST_SPIRIT_DEBUG_RULE(type_specifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(type_specifier);
            BOOST_SPIRIT_DEBUG_RULE(ptr_operator);
            BOOST_SPIRIT_DEBUG_RULE(cv_qualifier_seq);
            BOOST_SPIRIT_DEBUG_RULE(nested_name_specifier);
            BOOST_SPIRIT_DEBUG_RULE(parameter_declaration_list_helper);
            BOOST_SPIRIT_DEBUG_RULE(parameter_declaration);
            BOOST_SPIRIT_DEBUG_RULE(decl_specifier_seq);

            BOOST_SPIRIT_DEBUG_RULE(COMMA);
            BOOST_SPIRIT_DEBUG_RULE(LEFTPAREN);
            BOOST_SPIRIT_DEBUG_RULE(RIGHTPAREN);
            BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACKET);
            BOOST_SPIRIT_DEBUG_RULE(LEFTBRACKET);
            BOOST_SPIRIT_DEBUG_RULE(STAR);
            BOOST_SPIRIT_DEBUG_RULE(AND);
            BOOST_SPIRIT_DEBUG_RULE(ELLIPSIS);
            BOOST_SPIRIT_DEBUG_RULE(EPSILON);
            BOOST_SPIRIT_DEBUG_RULE(COMMA);
            BOOST_SPIRIT_DEBUG_RULE(LEFTPAREN);
            BOOST_SPIRIT_DEBUG_RULE(RIGHTPAREN);
            BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACKET);
            BOOST_SPIRIT_DEBUG_RULE(LEFTBRACKET);
            BOOST_SPIRIT_DEBUG_RULE(STAR);
            BOOST_SPIRIT_DEBUG_RULE(AND);
            BOOST_SPIRIT_DEBUG_RULE(ASSIGN);
            BOOST_SPIRIT_DEBUG_RULE(EPSILON);
            BOOST_SPIRIT_DEBUG_RULE(LEFTPAREN);
            BOOST_SPIRIT_DEBUG_RULE(RIGHTPAREN);
            BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACKET);
            BOOST_SPIRIT_DEBUG_RULE(LEFTBRACKET);
            BOOST_SPIRIT_DEBUG_RULE(STAR);
            BOOST_SPIRIT_DEBUG_RULE(AND);
            BOOST_SPIRIT_DEBUG_RULE(EPSILON);
            BOOST_SPIRIT_DEBUG_RULE(CONST_);
            BOOST_SPIRIT_DEBUG_RULE(VOLATILE);
            BOOST_SPIRIT_DEBUG_RULE(STAR);
            BOOST_SPIRIT_DEBUG_RULE(COLON_COLON);
            BOOST_SPIRIT_DEBUG_RULE(COMMA);
            BOOST_SPIRIT_DEBUG_RULE(ELLIPSIS);
            BOOST_SPIRIT_DEBUG_RULE(ASSIGN);
            BOOST_SPIRIT_DEBUG_RULE(EPSILON);
    }
}  // namespace cnome
#endif // DECLARATORS_H
